/*
 * Copyright (C) 2009 M. Hautle.
 * 
 * This file is part of TrackedBean.
 * 
 * TrackedBean is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * TrackedBean is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with TrackedBean. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.trackedbean.copier.internal;

import ch.msoftch.internal.*;
import ch.simpleel.accessors.*;
import ch.trackedbean.copier.*;

/**
 * Super class for {@link IMappingHolder}s which were using two normal properties.
 * 
 * @author M. Hautle
 */
public abstract class AbstractSimpleMappingHolder implements IMappingHolder {
    /** Object representing an unaccessible/undefined value. */
    protected static final Object UNDEFINED = new Object();

    /** The source value accessor. */
    protected final IValueAccessor srcProp;

    /** The destination accessor (on the object holding the mapping annotations). */
    protected final IValueAccessor dstProp;

    /** Flag indicating if the property should be fetched lazy. */
    protected final boolean lazy;

    /** Flag indicating if {@link #copyDst2Src(Object, Object, IMappingContext)} should be executed. */
    protected final boolean readOnly;

    /** The profile to which this mapping belongs. */
    protected final String profile;

    /**
     * Default constructor.
     * 
     * @param src The source accessor
     * @param dst The destination accessor (on the object holding the mapping annotations)
     * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link #copyDst2Src(Object, Object, IMappingContext)} will not be executed
     * @param lazy Flag indicating if the property should be fetched lazy
     * @param profile The profile to which this mapping belongs
     */
    protected AbstractSimpleMappingHolder(IValueAccessor src, IValueAccessor dst, boolean readOnly, boolean lazy, String profile) {
        if (src == null)
            throw new IllegalArgumentException("The source accessor must be set!");
        if (dst == null)
            throw new IllegalArgumentException("The destination accessor must be set!");
        this.srcProp = src;
        this.dstProp = dst;
        this.lazy = lazy;
        this.readOnly = readOnly;
        this.profile = profile;
    }

    /**
     * Returns if the mapped property should be fetched lazy.
     * 
     * @return True if this mapping should be fetched lazy
     */
    public boolean isLazy() {
        return lazy;
    }

    /**
     * Returns wherever this mapping is readonly (so that {@link #copyDst2Src(Object, Object, IMappingContext)} will not be executed).
     * 
     * @return True if it is readonly
     */
    public boolean isReadOnly() {
        return readOnly;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void copySrc2Dst(Object src, Object dst, IMappingContext context) throws TechnicalException {
        try {
            copyToDestination(src, dst, context);
        } catch (Exception e) {
            throw new TechnicalException("Error while copying!", e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void copyDst2Src(Object src, Object dst, IMappingContext context) throws TechnicalException {
        if (!readOnly)
            try {
                copyToSource(src, dst, context);
            } catch (Exception e) {
                throw new TechnicalException("Error while copying!", e);
            }
    }

    /**
     * Copies the value from the src object into the dst object.
     * 
     * @param dst The object holding the mapping
     * @param src The other object
     * @param context The mapping context
     * @throws Exception If something goes wrong
     */
    protected abstract void copyToDestination(Object src, Object dst, IMappingContext context) throws Exception;

    /**
     * Copies the value from the dst object into the src object.
     * 
     * @param dst The object holding the mapping
     * @param src The other object
     * @param context The mapping context
     * @throws Exception If something goes wrong
     */
    protected abstract void copyToSource(Object src, Object dst, IMappingContext context) throws Exception;

    /**
     * {@inheritDoc}
     */
    @Override
    public IValueAccessor getSourceAccessor() {
        return srcProp;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public IValueAccessor getDestinationAccessor() {
        return dstProp;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object getDstValue(Object dst) {
        return dstProp.getValue(dst, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object getSrcValue(Object src) {
        return srcProp.getValue(src, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getProfile() {
        return profile;
    }
}
